/*************************************************************************
	> File Name: grammar_opt.c
	> function: 语音听写(iFly Auto Transform)技术能够实时地将语音转换成对应的文字。
	> Author:卢孙远(Simon)
	> company: GDOU
	> Mail: lsy476941913@live.com 
	> Created Time: 2017年03月28日 星期二 12时33分36秒
 ************************************************************************/
#include "../include/grammar_opt.h"

const char * ASR_RES_PATH   = "fo|res/asr/common.jet"; //离线语法识别资源路径，路径方式（fo）和文件描述符方式（fd）
const char * GRM_BUILD_PATH = "res/asr/GrmBuilld"; //构建离线语法识别网络生成数据保存路径
const char * GRM_FILE       = "cmd.bnf"; //构建离线识别语法网络所用的语法文件


int build_grm_cb(int ecode, const char *info, void *udata)
{
	UserData *grm_data = (UserData *)udata;

	if (NULL != grm_data) {
		grm_data->build_fini = 1;
		grm_data->errcode = ecode;
	}

	if (MSP_SUCCESS == ecode && NULL != info) {
		printf("构建语法成功！ 语法ID:%s\n", info);
		if (NULL != grm_data)
			snprintf(grm_data->grammar_id, MAX_GRAMMARID_LEN - 1, "%s", info);
	}
	else
		printf("构建语法失败！%d\n", ecode);

	return 0;
}

int build_grammar(UserData *udata)
{
	FILE *grm_file           = NULL;	//语法文件指针
	char *grm_content        = NULL;	//语法文件内容
	unsigned int grm_cnt_len = 0;
	int ret                  = 0;
	char *grm_build_params   = calloc(1, MAX_PARAMS_LEN);


	//cmd.bnf语法文件
	grm_file = fopen(GRM_FILE, "rb");	
	if(NULL == grm_file) {
		printf("打开\"%s\"文件失败！[%s]\n", GRM_FILE, strerror(errno));
		return -1; 
	}

	fseek(grm_file, 0, SEEK_END);
	grm_cnt_len = ftell(grm_file);
	fseek(grm_file, 0, SEEK_SET);

	grm_content = (char *)malloc(grm_cnt_len + 1);
	if (NULL == grm_content)
	{
		printf("内存分配失败!\n");
		fclose(grm_file);
		grm_file = NULL;
		return -1;
	}
	fread((void*)grm_content, 1, grm_cnt_len, grm_file);
	grm_content[grm_cnt_len] = '\0';
	fclose(grm_file);
	grm_file = NULL;

	snprintf(grm_build_params, MAX_PARAMS_LEN - 1, 
		"engine_type = local, \
		asr_res_path = %s, sample_rate = %d, \
		grm_build_path = %s, ",
		ASR_RES_PATH,	//"fo|res/asr/common.jet"
		SAMPLE_RATE_16K,
		GRM_BUILD_PATH	//"res/asr/GrmBuilld"
		);
	ret = QISRBuildGrammar("bnf", grm_content, grm_cnt_len, grm_build_params, build_grm_cb, udata);

	free(grm_content);
	free(grm_build_params);
	grm_content = NULL;

	return ret;
}





static char *g_result = NULL;
static unsigned int g_buffersize = BUFFER_SIZE;

void on_result(const char *result, char is_last)
{
	if(result)
	{
		size_t left = g_buffersize - 1 - strlen(g_result);
		size_t size = strlen(result);

		if(left < size)
		{
			g_result = (char*)realloc(g_result, g_buffersize + BUFFER_SIZE);

			if(g_result)
				g_buffersize += BUFFER_SIZE;
			else
			{
				printf("mem alloc failed\n");
				return;
			}
		}
		strncat(g_result, result, size);
		show_result(g_result, is_last);
	}
}
void on_speech_begin()
{
	if(g_result)
	{
		free(g_result);
	}
	g_result = (char*)malloc(BUFFER_SIZE);
	g_buffersize = BUFFER_SIZE;
	memset(g_result, 0, g_buffersize);

	printf("Start Listening...\n");
}
void on_speech_end(int reason)
{
	if (reason == END_REASON_VAD_DETECT)
		printf("\nSpeaking done \n");
	else
		printf("\nRecognizer error %d\n", reason);
}

static void demo_file(const char* audio_file, const char* session_begin_params)
{
	int	errcode = 0;
	FILE*	f_pcm = NULL;
	char*	p_pcm = NULL;
	unsigned long pcm_count = 0;
	unsigned long pcm_size  = 0;
	unsigned long read_size = 0;

	struct speech_rec iat;
	struct speech_rec_notifier recnotifier =
	{
		on_result,
		on_speech_begin,
		on_speech_end
	};

	if (NULL == audio_file)
		goto iat_exit;

	f_pcm = fopen(audio_file, "rb");
	if (NULL == f_pcm)
	{
		printf("\nopen [%s] failed: %s\n",
				audio_file, strerror(errno));
		goto iat_exit;
	}

	/*
	*保存音频文件大小
	*/
	fseek(f_pcm, 0, SEEK_END);
	pcm_size = ftell(f_pcm);
	fseek(f_pcm, 0, SEEK_SET);

	p_pcm = (char *)malloc(pcm_size);//为音频文件指针分配空间
	if (NULL == p_pcm)
	{
		printf("\nout of memory! \n");
		goto iat_exit;
	}
	read_size = fread((void *)p_pcm, 1, pcm_size, f_pcm);//将音频文件存入p_pcm指针
	if (read_size != pcm_size)
	{
		printf("\nread [%s] error!\n", audio_file);
		goto iat_exit;
	}

	errcode = sr_init(&iat, session_begin_params, SR_USER, &recnotifier);
	if(errcode != 0)
	{
		printf("speech recognizer init failed : %d\n", errcode);
		goto iat_exit;
	}

	errcode = sr_start_listening(&iat);
	if(errcode != 0)
	{
		printf("\nsr_start_listening failed! error code:%d\n", errcode);
		goto iat_exit;
	}

	while(1)
	{
		unsigned int len = 10 * FRAME_LEN; /* 200ms audio */
		int ret = 0;

		if (pcm_size < 2 * len)
			len = pcm_size;
		if (len <= 0)
			break;

		ret = sr_write_audio_data(&iat, &p_pcm[pcm_count], len);

		if(0 != ret)
		{
			printf("\nwrite audio data failed! error code:%d\n", ret);
			goto iat_exit;
		}

		pcm_count += (long)len;
		pcm_size  -= (long)len;		
	}

	errcode = sr_stop_listening(&iat);
	if(errcode)
	{
		printf("\nsr_stop_listening failed! error code:%d \n", errcode);
		goto iat_exit;
	}

iat_exit:
	if(NULL != f_pcm)
	{
		fclose(f_pcm);
		f_pcm = NULL;
	}
	if(NULL != p_pcm)
	{
		free(p_pcm);
		p_pcm = NULL;
	}

	sr_stop_listening(&iat);
	sr_uninit(&iat);
}

int run_asr(UserData *udata)
{
	char *asr_params = calloc(1, MAX_PARAMS_LEN);
	const char *asr_audiof = NULL;

	//离线语法识别参数设置
	snprintf(asr_params, MAX_PARAMS_LEN - 1, 
			"engine_type = local, "
			"asr_res_path = %s, sample_rate = %d, "
			"grm_build_path = %s, local_grammar = %s, "
			"result_type = xml, result_encoding = UTF-8, ",
			ASR_RES_PATH,
			SAMPLE_RATE_16K,
			GRM_BUILD_PATH,
			udata->grammar_id
			);

	init_sock();	//初始化socket，等待客户端连接。
	while(1)
	{
		asr_audiof = get_audio_file();	//从对端获得音频数据
		demo_file(asr_audiof, asr_params); 
	}

	free(asr_params);
	return 0;
}
